<!DOCTYPE html>
<html >
<head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    
    <title>网页自适应显示WebP图片 | xilixili.net</title>
    <meta name="renderer" content="webkit">
    <meta name="HandheldFriendly" content="True">
    <meta name="MobileOptimized" content="320">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

    <meta name="description" content="生命不息，折腾不止。
起因最近上传了个背景图，加载的非常慢，才发现上传了个1M多的图。优化手段无非就是做做图片裁剪已经质量压缩，网上确实也有不少的分析压缩的方法，但基本都是jpeg和png等。偶然发现最近流行的WebP格式，又是对图片压缩的一大进步，可以大幅优化流量。
WebP就不多做介绍了，有兴趣的百度之。总之这个格式比等质量的png和jpg图片要小不少。但是作为浏览器的通病，各个浏览器未必能够">

    <meta name="twitter:card" content="summary">
    <meta name="twitter:title" content="网页自适应显示WebP图片 | xilixili.net">
    <meta name="twitter:description" content="生命不息，折腾不止。
起因最近上传了个背景图，加载的非常慢，才发现上传了个1M多的图。优化手段无非就是做做图片裁剪已经质量压缩，网上确实也有不少的分析压缩的方法，但基本都是jpeg和png等。偶然发现最近流行的WebP格式，又是对图片压缩的一大进步，可以大幅优化流量。
WebP就不多做介绍了，有兴趣的百度之。总之这个格式比等质量的png和jpg图片要小不少。但是作为浏览器的通病，各个浏览器未必能够">

    <meta property="og:type" content="article">
    <meta property="og:title" content="网页自适应显示WebP图片 | xilixili.net">
    <meta property="og:description" content="生命不息，折腾不止。
起因最近上传了个背景图，加载的非常慢，才发现上传了个1M多的图。优化手段无非就是做做图片裁剪已经质量压缩，网上确实也有不少的分析压缩的方法，但基本都是jpeg和png等。偶然发现最近流行的WebP格式，又是对图片压缩的一大进步，可以大幅优化流量。
WebP就不多做介绍了，有兴趣的百度之。总之这个格式比等质量的png和jpg图片要小不少。但是作为浏览器的通病，各个浏览器未必能够">

    
    <meta name="author" content="rangerlee">
    
    <link rel="stylesheet" href="/css/vno.css">
    <link rel="stylesheet" href="/css/font-awesome.min.css">

    
    <link rel="icon" href="/images/avatar-small.png">
    

    <meta name="generator" content="hexo"/>
    
    <link rel="alternate" type="application/rss+xml" title="xilixili.net" href="/atom.xml">
    

    <link rel="canonical" href="xilixili.net/2017/02/07/webp/"/>

                 
</head>

<body class="home-template no-js">
    <script src="//cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
    <script src="/js/main.js"></script>
    <span class="mobile btn-mobile-menu">
        <i class="fa fa-list btn-mobile-menu__icon"></i>
        <i class="fa fa-angle-up btn-mobile-close__icon hidden"></i>
    </span>

    
<header class="panel-cover panel-cover--collapsed">
  <div class="panel-main">
    <div class="panel-main__inner panel-inverted">
    <div class="panel-main__content">

        <h1 class="panel-cover__title panel-title"><a href="/" title="访问首页 xilixili.net">xilixili.net</a></h1>
        
        <span class="panel-cover__subtitle panel-subtitle"><!-- 生活と技术の杂记 --></span>
        
        <hr class="panel-cover__divider">
        
        <p class="panel-cover__description">生活と技术の杂记</p>
        
	<hr class="panel-cover__divider panel-cover__divider--secondary">

        <div class="navigation-wrapper">
          <div>
          <nav class="cover-navigation cover-navigation--primary">
            <ul class="navigation">
              <li class="navigation__item"><a href="/#blog" title="访问博客" class="blog-button">博客</a></li>
            
            </ul>
          </nav>
          </div>
          <div>
          <nav class="cover-navigation navigation--social">
  <ul class="navigation">

  <!-- Weibo-->
  

  <!-- Github -->
  
  <li class="navigation__item">
    <a href="https://github.com/rangerlee" title="查看我的GitHub主页" target="_blank">
      <i class="social fa fa-github"></i>
      <span class="label">Github</span>
    </a>
  </li>


<!-- Stack Overflow -->
        

  <!-- Google Plus -->
  

<!-- Facebook -->

  
<!-- Twitter -->

  

  <li class="navigation__item">
    <a href="/atom.xml" title="RSS" target="_blank">
      <i class="social fa fa-rss"></i>
      <span class="label">RSS</span>
    </a>
  </li>


  <li class="navigation__item">
    <a href="mailto:http://mail.qq.com/cgi-bin/qm_share?t=qm_mailme&amp;email=RzUmKSAiNSsiIgchKD8qJi4raSQoKg" title="邮件联系我" target="_blank">
      <i class="social fa fa-envelope"></i>
      <span class="label">Email</span>
    </a>
  </li>


  </ul>
</nav>

          </div>
        </div>

      </div>

    </div>

    <div class="panel-cover--overlay cover-alpha"></div>
  </div> 
</header>
<script type="text/javascript">
var side = document.getElementsByClassName("panel-cover")[0];
function checkWebp() {
	try{
		return(document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0);
	}catch(err) {
		return false;
	}
};

if(checkWebp()) {
	side.style.backgroundImage = "url('/images/background-cover.jpg.webp')";
} else {
	side.style.backgroundImage = "url('/images/background-cover.jpg')";
}
</script>


    <div class="content-wrapper">
        <div class="content-wrapper__inner">
            <article class="post-container post-container--single">

  <header class="post-header">
    <div class="post-meta">
      <time datetime="2017-02-07T12:44:00.000Z" class="post-list__meta--date date">2017-02-07</time> &#8226; <span class="post-meta__tags tags">
  <a class="tag-link" href="/tags/技术/">技术</a>
 </span>
      <span class="page-pv">
       阅读 <span id="busuanzi_value_page_pv"><i class="fa fa-spinner fa-spin"></i></span>
      </span> 
   
    </div>
    <h1 class="post-title">网页自适应显示WebP图片</h1>
  </header>

  <section class="post">
    <p>生命不息，折腾不止。</p>
<h3 id="起因"><a href="#起因" class="headerlink" title="起因"></a>起因</h3><p>最近上传了个背景图，加载的非常慢，才发现上传了个1M多的图。优化手段无非就是做做图片裁剪已经质量压缩，网上确实也有不少的分析压缩的方法，但基本都是jpeg和png等。偶然发现最近流行的WebP格式，又是对图片压缩的一大进步，可以大幅优化流量。</p>
<p>WebP就不多做介绍了，有兴趣的百度之。总之这个格式比等质量的png和jpg图片要小不少。但是作为浏览器的通病，各个浏览器未必能够支持，据介绍当前chrome和opera已经支持了，IE系肯定暂时没有支持。要使用这种图片看来得做适配，大致我搜索到的有两种方法：</p>
<ul>
<li>采用插件支持，让页面支持WebP格式的解码（应该是通过flash）</li>
<li>采用HTML通过picture标记实现两种图片加载</li>
<li>懒加载，通过JavaScript控制加载的资源类型</li>
</ul>
<p>以上方式是客户端常用的方式，不过像第二种方式需要刻意去修改HTML源码不是很方便，其他方式还行。当然除了上述方式外，还有一些在服务端可以处理的办法，首先是我根据实际测试总结出来的。</p>
<h3 id="nginx处理方法"><a href="#nginx处理方法" class="headerlink" title="nginx处理方法"></a>nginx处理方法</h3><p>一般来讲，浏览器在请求服务端时候会携带支持的格式，目前支持webp的浏览器都会在请求Accept中携带 <code>image/webp</code>，这是最简单的服务端检测方法，但是，总不能在代码中去干这个事情吧，况且本站还是静态博客。这个时候想到了牛逼的nginx，nginx有丰富的插件，在不了解有没有类似的插件的情况下完全可以去写一个。使用类似rewrite的功能去跳转。</p>
<p>查询资料发现应该可以通过nginx配置try_files加正则表达式的方式搞定，但是对nginx这块语法不是特别熟练外加配置写的一直不正确，暂时用nginx的lua插件测试下。需要准备一个正常图片如1.png，另外生成对应的webp格式如1.png.webp，统一访问webp资源。nginx根据Accept进行判断是否支持WebP，如果不支持跳转到非webp版本，即去掉webp后缀即可。</p>
<p>默认安装的nginx是没有lua功能的，需要单独编译，这里我偷懒直接使用老罗捐助过的 <code>OpenResty</code>。在CentOS下可以直接添加repo进行yum安装，详情参见<a href="http://openresty.org/cn/linux-packages.html" title="http://openresty.org/cn/linux-packages.html" target="_blank" rel="noopener">http://openresty.org/cn/linux-packages.html</a>，安装完成之后，配置 <code>/usr/local/openresty/nginx/conf/nginx.conf</code>，在location下添加类似如下代码（其实是一段lua）</p>
<figure class="highlight lua"><table><tr><td class="code"><pre><span class="line">rewrite_by_lua_block &#123;</span><br><span class="line">  <span class="keyword">local</span> m, _ = ngx.re.<span class="built_in">match</span>(ngx.var.uri, <span class="string">"^.*?\\.(webp)$"</span>)</span><br><span class="line">  <span class="keyword">if</span> m <span class="keyword">then</span></span><br><span class="line">     <span class="keyword">local</span> a = ngx.req.get_headers()[<span class="string">"Accept"</span>]</span><br><span class="line">     <span class="keyword">local</span> i, _ = <span class="built_in">string</span>.<span class="built_in">find</span>(a, <span class="string">"image/webp"</span>)</span><br><span class="line">     <span class="keyword">if</span> i == <span class="literal">nil</span> <span class="keyword">then</span></span><br><span class="line">        <span class="keyword">local</span> u, _ = <span class="built_in">string</span>.<span class="built_in">gsub</span>(ngx.var.uri, <span class="string">".webp"</span>, <span class="string">""</span>)</span><br><span class="line">        ngx.req.set_uri(u)</span><br><span class="line">     <span class="keyword">end</span></span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>其他根据实际需要配置。配置完成并启动nginx之后，写一个测试工程 <code>test.html</code> 及 <code>test.jpg</code> 和 <code>test.jpg.webp</code> 资源并部署到html目录。</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">"test.jpg.webp"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>除了上面笨拙的办法，Google大神们还提供了个pagespeed模块。这个模块甚是强大，可以对网页进行速度优化，比如合并CSS，压缩空白，合并javascript等等，当然在支持webp的浏览器上会直接返回webp格式，更牛逼的是此过程是自动化的（包括webp格式的生成），不需要人为处理。</p>
<p>PageSpeed模块官网 <a href="https://developers.google.com/speed/pagespeed/module/" target="_blank" rel="noopener">https://developers.google.com/speed/pagespeed/module/</a></p>
<p>当然也是需要重新编译nginx的，并且在nginx配置中启用该功能</p>
<figure class="highlight shell"><table><tr><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 启用ngx_pagespeed</span></span><br><span class="line">pagespeed on;</span><br><span class="line">pagespeed FileCachePath /tmp/cache/ngx_pagespeed_cache;</span><br></pre></td></tr></table></figure>
<p>启用之后速度杠杠的，当然据说（想想也是）副作用就是服务端的CPU和内存也很高，有点得不偿失。</p>
<h3 id="本站方案"><a href="#本站方案" class="headerlink" title="本站方案"></a>本站方案</h3><p>本站是hexo静态博客，主要的大图片在markdown博客中，我打算采用picture标记的方式实现，picture标记的思路是采用H5的picture标记来设置图片资源，如</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">picture</span> <span class="attr">class</span>=<span class="string">"picture"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">source</span> <span class="attr">type</span>=<span class="string">"image/webp"</span> <span class="attr">srcset</span>=<span class="string">"image.jpg.webp"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">img</span> <span class="attr">class</span>=<span class="string">"image"</span> <span class="attr">src</span>=<span class="string">"image.jpg"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">picture</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>如果浏览器支持WebP格式则加载 <code>image.jpg.webp</code>，否则加载<code>image.jpg</code>。那么首先就是需要将hexo生成的代码修改为生成如上代码的方式。hexo采用的是marked引擎，好在修改比较简单，打开目录下 <code>node_modules/marked/lib/marked.js</code>，找到 <code>Renderer.prototype.image</code> 函数实现，修改为以下版本</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line">Renderer.prototype.image = <span class="function"><span class="keyword">function</span>(<span class="params">href, title, text</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> re = <span class="keyword">new</span> <span class="built_in">RegExp</span>(<span class="string">"([a-zA-Z0-9-_]+)\.(png|jpg|gif|jpeg)\.webp$"</span>);</span><br><span class="line">  <span class="keyword">if</span>(re.test(href))&#123;</span><br><span class="line">    <span class="keyword">var</span> out = <span class="string">'&lt;picture class="picture"&gt;'</span></span><br><span class="line">    out += <span class="string">'&lt;source type="image/webp" srcset="'</span>+ href +<span class="string">'"&gt;'</span>;</span><br><span class="line">    out += <span class="string">'&lt;img class="image" src="'</span>+ href.substring(<span class="number">0</span>, href.length<span class="number">-5</span>);</span><br><span class="line">    out += <span class="string">'" alt="'</span> + text + <span class="string">'"'</span>;</span><br><span class="line">	<span class="keyword">if</span> (title) &#123;</span><br><span class="line">	  out += <span class="string">' title="'</span> + title + <span class="string">'"'</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	out += <span class="keyword">this</span>.options.xhtml ? <span class="string">'/&gt;'</span> : <span class="string">'&gt;'</span>;</span><br><span class="line">	out += <span class="string">'&lt;/picture&gt;'</span>;</span><br><span class="line">	<span class="keyword">return</span> out;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">	<span class="keyword">var</span> out = <span class="string">'&lt;img src="'</span> + href + <span class="string">'" alt="'</span> + text + <span class="string">'"'</span>;</span><br><span class="line">	<span class="keyword">if</span> (title) &#123;</span><br><span class="line">	  out += <span class="string">' title="'</span> + title + <span class="string">'"'</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	out += <span class="keyword">this</span>.options.xhtml ? <span class="string">'/&gt;'</span> : <span class="string">'&gt;'</span>;</span><br><span class="line">	<span class="keyword">return</span> out;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>当然和之前一样，约定我们写markdown文档时候设置的图片是webp格式的，同时保留原始图片，如 <code>1.png</code> 和 <code>1.png.webp</code>。这样修改之后，hexo生成出来的代码可以根据markdown里面的图片进行适配。</p>
<p>剩下的问题就是样式问题了，如果有特别的图像样式，需要修改原来的主题中的img样式进行迁移。将原来的img样式迁移到 <code>.image</code> 。因为我是博客文章中使用基本没什么问题，如果要完全使用，还需要注意CSS设置的图片（如背景图片）并不能自适应，请注意！</p>
<h3 id="背景图片"><a href="#背景图片" class="headerlink" title="背景图片"></a>背景图片</h3><p>如上在CSS中无法处理实现，在Hexo博客中采用的框架模式，那么进行统一的框架处理即可，但是WebP的支持情况就是在浏览器端才可以确认，因此在页面框架中增加一段加载完成后执行的JavaScript代码，用来检测和设置背景图片。</p>
<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">var</span> side = <span class="built_in">document</span>.getElementsByClassName(<span class="string">"panel-cover"</span>)[<span class="number">0</span>];</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">checkWebp</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">	<span class="keyword">try</span>&#123;</span><br><span class="line">		<span class="keyword">return</span>(<span class="built_in">document</span>.createElement(<span class="string">'canvas'</span>).toDataURL(<span class="string">'image/webp'</span>).indexOf(<span class="string">'data:image/webp'</span>) == <span class="number">0</span>);</span><br><span class="line">	&#125;<span class="keyword">catch</span>(err) &#123;</span><br><span class="line">		<span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(checkWebp()) &#123;</span><br><span class="line">	side.style.backgroundImage = <span class="string">"url('/images/background-cover.jpg.webp')"</span>;</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">	side.style.backgroundImage = <span class="string">"url('/images/background-cover.jpg')"</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>当然，具体的图片是在框架中根据配置生成的，大致原理如此，基本可以实现全站大图的WebP支持，当然小图片太多的话并且这么设置的话还是非常麻烦的，使用原始的格式即可。</p>

  </section>

</article>

<section class="read-more">
           
    
               
            <div class="read-more-item">
                <span class="read-more-item-dim">最近的文章</span>
                <h2 class="post-list__post-title post-title"><a href="/2017/02/22/zookeeper/" title="C++集成zookeeper客户端">C++集成zookeeper客户端</a></h2>
                <p class="excerpt">
                
                zookeeper是Java下常用的分布式应用程序协调服务。因接触到Java业务系统的一些架构，比如流行的微服务架构等等都采用zookeeper做服务发现。某些系统服务可以采用其他语言如C\C++实现来提升性能或者实现某些特殊功能。
本文为C++集成zookeeper客户端的开发调研。
开始zook
                &hellip;
                </p>
                <div class="post-list__meta"><time datetime="2017-02-22T03:39:00.000Z" class="post-list__meta--date date">2017-02-22</time> &#8226; <span class="post-list__meta--tags tags">
  <a class="tag-link" href="/tags/技术/">技术</a>
</span><a class="btn-border-small" href="/2017/02/22/zookeeper/">继续阅读</a></div>
                           
            </div>
        
        
               
            <div class="read-more-item">
                <span class="read-more-item-dim">更早的文章</span>
                <h2 class="post-list__post-title post-title"><a href="/2017/01/18/blog/" title="博客迁移Hexo">博客迁移Hexo</a></h2>
                <p class="excerpt">
                
                用了大半年的Ink Paper静态博客引擎，时间长了就感觉风格有点过于素雅了，感觉一点色彩都没有（文档列表基本也没设置图），而且不知为何官网都无法访问了，不知何故。闲话不说，首先谈谈我用这个GO语言开发的博客系统使用这么长时间的感受

简洁，非常适合阅读，基本纯黑白文字
主题太少，貌似就两个主题，而
                &hellip;
                </p>
                <div class="post-list__meta"><time datetime="2017-01-18T02:54:00.000Z" class="post-list__meta--date date">2017-01-18</time> &#8226; <span class="post-list__meta--tags tags">
  <a class="tag-link" href="/tags/技术/">技术</a>
</span><a class="btn-border-small" href="/2017/01/18/blog/">继续阅读</a></div>
                       
            </div>
        
     
   
   
  
</section>



	<script>
	(function(){
		var bp = document.createElement('script');
		var curProtocol = window.location.protocol.split(':')[0];
		if (curProtocol === 'https') {
			bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';        
		}
		else {
			bp.src = 'http://push.zhanzhang.baidu.com/push.js';
		}
		var s = document.getElementsByTagName("script")[0];
		s.parentNode.insertBefore(bp, s);
	})();
	</script>



<script>
(function(){
var src = (document.location.protocol == "http:") ? "http://js.passport.qihucdn.com/11.0.1.js?8612a7fa26d7ba4562be733ae33649b1":"https://jspassport.ssl.qhimg.com/11.0.1.js?8612a7fa26d7ba4562be733ae33649b1";
document.write('<script src="' + src + '" id="sozz"><\/script>');
})();
</script>



            <footer class="footer">
    <span class="footer__copyright">
        &copy; 2023 rangerlee - 本站点采用 <a href="http://creativecommons.org/licenses/by-nc-sa/4.0/">知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议</a>
       
    </span>
    <span class="footer__copyright">
             - 本站基于开源 <a href="http://hexo.io">Hexo</a> 搭建，采用 <a href="https://github.com/rangerlee/hexo-theme-new-vno">hexo-theme-new-vno</a> 主题，修改自 <a href="https://github.com/monniya/hexo-theme-new-vno ">new-vno</a> 主题  <a href="http://www.beian.miit.gov.cn">皖ICP备16009457号</a>
         </span>
       
    
    
</footer>


        </div>
    </div>

     
    
    <script>
        var _hmt = _hmt || [];
        (function() {
            var hm = document.createElement("script");
            hm.src = "//hm.baidu.com/hm.js?bab4f71524319c10819bcae280021624";
            var s = document.getElementsByTagName("script")[0]; 
            s.parentNode.insertBefore(hm, s);
        })();
    </script>



    <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    
    
</body>
</html>
